<?php
/**
 * Created by PhpStorm.
 * User: inhere
 * Date: 2016/2/19
 * Time: 15:30
 */

namespace app\parsers;

use app\helpers\exceptions\FileReadException;
use Slim;
use slimExt\DataCollector;
use app\extensions\MderPage;

/**
 * Class DefaultParser
 * @package app\parsers
 *
 * @property-read string $outputFile
 * @property $dataFile
 */
class DefaultParser extends AbstractParser
{

    /**
     * parse data file, return the parsed content.
     * @return string
     * @throws FileReadException
     */
    public function parse()
    {
        $dataFile = $this->pager->dataFile;

        // read content
        if ( ( $content = file_get_contents($dataFile) ) === false ) {
            throw new FileReadException("An error occurred while reading the file. File: {$dataFile}");
        }

        list($setting, $content) = $this->splitDataContent($content);

        // $this->pager->handle();

        $content = $this->collectPageAttr($setting, $dataFile)
                        ->replacePageVar($content);

        // parse markdown text
        return $this->parseMarkdown($content);
    }

    /**
     * @param string $content
     * @return array
     */
    public function splitDataContent($content)
    {
       // $regex = '/^(?:\{###\n?)(?:[\s\S]*)(?:###\})\n?/';
       // if( !preg_match($regex, $text, $matches) ) {
       //     return $text;
       // }
       // $setting = $matches[0];

        // "/^(?:\{###\n?)/"
        $regex = '/^(?:\\' .$this->options['tagStart'] . '\n?)/';
        $setting = '';
        $content = trim($content);

        // if have settings, do parse it
        if ( preg_match($regex, $content) && strpos($content, $this->options['tagEnd']) !== false ) {

            // split string to array
            list($setting, $content) = preg_split('/(?:###\})\n?/', $content, 2);

            $setting = substr($setting, strlen($this->options['tagStart']) );
        }

        return [trim($setting), trim($content)];
    }

    /**
     * collect custom page attribute
     * require start tag '{###' and require end tag '###}' at data file
     * @param string $setting
     * @param string $dataFile
     * @param bool $onlyReturnSettings
     * @return array|static
     */
    public function collectPageAttr($setting, $dataFile='', $onlyReturnSettings=false)
    {
        $settings = DataCollector::parseYaml($setting);
        $this->pager->rawAttr = $settings;

        if ($onlyReturnSettings) {
            return $settings;
        }

        // allow override page setting in the data file.
        if ( isset($settings['config']) ) {
            Slim::get('config')->loadArray($settings['config']);
            unset($settings['config']);
        }

        $this->setAttrs($settings);

        // if no 'updateTime', will use '$dataFile' modify time.
        if ( !$this->attrs['updateTime'] && $dataFile && file_exists($dataFile) ) {
            $this->attrs['updateTime'] = filemtime($this->pager->dataFile);
        }

        // if no 'author', will use 'project.author' in project config.
        if ( !$this->attrs['author'] ) {
            $this->attrs['author'] = $this->getItem()->getOption('author', self::UNKNOWN);
        }

        if ( is_array($this->attrs['prevPage']) && isset($this->attrs['prevPage']['url']) ) {
            $this->attrs['prevPage']['url'] = $this->handleNPUrl($this->attrs['prevPage']['url']);
        }
        if ( is_array($this->attrs['nextPage']) && isset($this->attrs['nextPage']['url']) ) {
            $this->attrs['nextPage']['url'] = $this->handleNPUrl($this->attrs['nextPage']['url']);
        }

        return $this;
    }

    protected function handleNPUrl($url)
    {
        // empty or '../../'
        if ( !$url || !trim($url, '/.')) {
            return $url;
        }

        $len = strlen(MderPage::DEFAULT_SOURCE_SUFFIX);

        if ( !strpos($url, '.') ) {
            return $url . MderPage::DEFAULT_OUTPUT_SUFFIX;
        }

        return substr($url, -$len) == MderPage::DEFAULT_SOURCE_SUFFIX ? substr($url,0, -$len) : $url;
    }

    /**
     * replace Page Var, setting on data_config.json
     * @param string $text
     * @return string
     */
    protected function replacePageVar($text)
    {
        $pageVar = Slim::config()->get('varList');
        $newVarList = [];

        foreach ($pageVar as $name => $value) {
            $name = '{@' . trim($name) . '@}';
            $newVarList[$name] = $value;
        }

        unset($pageVar);

        return strtr($text, $newVarList);
    }
}